Most often, such data can be organized in a table with rows of information, each column representing a different type of data. For example, in the case of processes running on a system, rows might be sorted according to their unique process identifier, and columns might represent such values as CPU usage, memory usage, owner's name, time of creation, ...
The software used to view this type of information comes in different forms and shapes. Unix users might be familiar with the "top" application which presents rows of process data as lines of text, whereas RMON (Remote MONitoring) SNMP software usually uses multiple windows with graphical displays, curves, pie charts, multiple configuration dialog boxes, even 3D visualization modules to present network traffic, connection matrices, ...
In most cases, data comes from one or several tables. A common interface, graphical with menus, drag'n'drop capability, table widgets, textual and graphical data viewers such as multiple line graphs, bar and pie charts, could be used. The user could then sort table rows, select one or more cells, rows, columns, to launch viewers such as other tables, charts, ... best suited to the way data should be presented. In effect, what is needed is a spreadsheet that is capable of dealing with dynamically changing data.
Moodss (Modular Object Oriented Dynamic SpreadSheet) is an attempt at answering these needs. It is composed of a main part (the core) and an unlimited number of modules, loaded as the application is launched, each module interfacing to a specific type of data. The core is written in the great Tcl language (at http://www.harlequin.com/ and http://www.scriptics.com/) using object oriented techniques thanks to the stooop and scwoop packages (at http://www.harlequin.com/ and http://www.mygale.org/~jfontain/). The module function is to describe the type of data that it is also in charge of retrieving and formatting. Modules can be written in plain Tcl or C and optionally use dynamically linked libraries written in the C language (modules are packages in the Tcl sense).
Modules are loaded when moodss is started. One or more modules can be handled concurrently (starting with moodss version 3.0). This way, you may monitor data coming from any number of heterogeneous sources. Module names are specified in the command line and cannot be dynamically unloaded.
Versions 4.0 and up add a dashboard functionality: the current configuration (modules, viewers, poll time, windows sizes and placement, ...) can be saved in a file at any time, for later reuse (see the -f (--file) command line switch documentation).
Versions 4.3 and up support asynchronous modules (no polling needed as module data may change on its own). Note that any number of asynchronous and regular (synchronous) modules can be simultaneously loaded.
Since module data access is entirely customizable (through C code, Tcl, HTTP, ...) and since several modules can be loaded at once, applications for moodss become limitless. For example, comparing a remote database server CPU load and a network load from a probe on the same graph becomes possible.
As features are added to moodss, different ways of viewing data will be made available while the modules will stay the same. The goal of moodss is to become a nice feature packed generic way of viewing data. Moodss can be used to monitor any type of data, since the simplest cases can fit in a table with a single row.
As moodss is written in Tcl and uses well supported extensions (Tktable and BLT), it will run on most Tcl/Tk supported platforms: UNIX and Windows (I do not know if Tktable and BLT are available for the MacIntosh). Some modules may be specific to a platform, but the core is guaranteed to run on them all.
After reading and understanding this document, you should be able to write your own modules in order to monitor the data that you are interested in.
Moodss is free software. You can redistribute it and/or modify it under the terms described in the COPYRIGHT file or use the main window Help Copyright menu for more information.
For the current version (5.0), the following packages must be installed before attempting to install moodss (make sure to check the INSTALL file for the latest information):
The pie widgets, stooop and scwoop libraries are included in the
self contained moodss application file. Therefore, it is not required
to install the stooop, scwoop and tkpiechart packages, unless you want
to work on the moodss source code itself. However, should you want to get
more information on those extensions, you could find the latest versions:
The core will load one or more modules, whose names were passed as command line parameters or come from a save file, and will start displaying module data in one or more tables. The tables are then updated at the frequency defined by the poll time, which the user may change, or asynchronously for the relevant modules. For example, to launch moodss with the random module, just type:
$ wish moodss randomAll the module code and data are kept in a separate namespace. The module data is stored is a single array including some configuration data used when the module is loaded by the core, and variable data (displayed in the application table and eventual graphical viewers). If a module is synchronous, it must start updating its data when requested by the core. If a module is asynchronous, its data may be updated at any time. The synchronous or asynchronous nature is specified in the configuration data for the module.
The initial data tables represent the first data views, from which cells can be selected and when dropped through a drag'n'drop operation into a graph, bar chart, pie chart, summary table or free text iconic site, result in the creation of data viewers. In turn, these viewers can display more table cells, which when dropped into the viewer, result in the creation of corresponding data graph lines, chart bars, pie slices, table rows or text cells.
Any draggable data can be dropped in valid drop sites at any time. It is thus possible to drag several data cells from any table or any viewer into other ones, the trash, ... even if the data comes from different modules.
All data viewers can be moved and resized at will with the help of a simple internal window manager.
The current configuration (loaded modules, tables and viewers coordinates and sizes, poll time, main window size, ...) can be saved in a file at any time, so that an identical dashboard can be relaunched at a later time.
The message area is used to display status information, such as when the data is being updated, and help information, as the user moves the mouse pointer over sensitive areas, such as table column headers. Further help is provided through widget tips (also known as balloons) when appropriate, and of course the Help menu.
The window title shows the name of the loaded module(s) along with the poll time.
The File menu contains the Save, Save As and Exit menu entries, used to save the current configuration (modules and viewers), or gracefully quit the moodss application.
The Options menu (may not exist, see below) contains the Poll time entry which when selected launches the corresponding dialog box, as shown below:
The user can select a new poll time among the module choices from a spin entry widget, or directly type in a new value, as long as it is not smaller than the module minimum poll time, in which case a message dialog box warns the user.
When several modules are used, the minimum poll time is the greater of the minimum poll times of all modules. The default poll time (used when moodss is started) is the greater of the default poll times of all modules. The available choices in the poll time dialog box is the combination of all modules poll times.
The Poll time menu entry is available only when needed, which is not the case if all the loaded modules are asynchronous. If this case, the Options menu itself is not displayed.
Any data displayed in a table can be sorted at any time by simply clicking
on a column title. Clicking on the same column title again sorts the data
in opposite order, thus toggling between increasing and decreasing orders.
When sorting, the selected column is used as a reference, meaning that
all rows will be rearranged so that the selected column appears sorted,
with values either increasing or decreasing.
A little arrow indicator is placed to the right of the reference column
title label, pointing up or down depending on whether the sorting order
is decreasing or increasing.
Table columns can be interactively resized by holding the first mouse
button down on a column border. The mouse cursor is changed to an horizontal
double arrow on column borders to show this capability.
Aside from the main tables, graphical and textual viewers can be created for viewing table cell data behavior over time. Viewers can also be deleted, data views (such as pie slices, curves, ...) can be added or removed from existing viewers, ... These functions are all implemented using the drag and drop functionality described below.
Graphical viewers available at this time are BLT graph viewers (such as can be seen below), side-by-side bars charts, overlapped bars charts (only available when the BLT version 2.4 library is used), stacked bars charts, 2D pie charts and 3D pie charts*.
*note: if you know of any other nice viewers (like 3D graphs) that
work with Tcl, please let me know so I can integrate them. Many thanks
in advance...
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
There are 2 textual viewers.
The summary table displays for each row the cell label, the current,
average, minimum and maximum values since the row was created.
The free text viewer is an editable Tcl text widget with any number
(including zero) of embedded data cell windows. Data cells can be inserted
one or several at a time through a simple drop, as with the other viewers.
New data cell windows are inserted at the current insertion cursor position.
Data cells can be deleted by selecting then dropping any number of them
into the trash drop site. They can also be deleted using the keyboard Delete
and Backspace keys, which also work on the regular text, as well as the
expected other key bindings. When dropping data cells, each data cell window
is preceded by a relevant label text for the cell, which can later be edited
at any time.
Here is a screen shot of loaded ps and cpustats modules
with several graphical viewers:
Here is another shot featuring a free text viewer with loaded cpustats and memstats modules:
The Help menu contains Global help (actually launches an embedded HTML viewer with this very document), Modules help which displays all the loaded modules help texts, Copyright which displays the GPL (Gnu General Public License) document, Source Versions which display all the source code file names with their versions and About general information entries.
Only valid drop sites for the data being dragged are highlighted when the mouse cursor passes over them, thus guaranteeing error free operations (if there are no bugs, that is :).
In summary, data cells can be dragged from any table or any viewer into any viewer drop site icon, any viewer or the trash can.
Once a viewer exists, it also acts as a drop site for data cells, which may be dragged from any table or other viewers. Dropping one or more cells directly in the viewer results in corresponding lines, bars, slices or rows being created and automatically updated. Each new graphical element is assigned a new and different color.
You may delete one or more viewer elements (graph lines, bar chart bars,
pie charts slices, summary table rows or free text cell window) from a
viewer by selecting them (using the first mouse button) through their labels.
Several elements can be selected by depressing the control key as the first
mouse button is pressed. The selection can also be extended by depressing
the shift key along with the first mouse button. The pie slices can also
be directly selected by clicking on the slices themselves.
Then dragging from the viewer to the trash drop site (the bullet hole)
on the upper right side of the main window and releasing the first mouse
button result in the corresponding viewer elements to be destroyed. If
there are no remaining elements, the viewer itself (graph, bar chart, pie
or summary table) is destroyed. The free text viewer can only be deleted
when completely emptied of any text and data cell window: it can then
be dropped into the trash.
Any viewer is also a drag site. It requires selecting one or more viewer elements before initiating the drag operation from any selected element in the viewer. If there are no selected elements, dragging is impossible: the mouse cursor is not changed into the drag circular cursor.
If a viewer contains no elements, then the viewer itself can be dragged and dropped into the trash.
Once moodss has been launched with one or several modules and tables have been moved, resized, viewers created, moved and resized, the current configuration can be saved in a .moo file, and later reused by passing the corresponding file name with the -f (--file) command line switch.
For moodss version 4.0 and above, the following information is saved in the file (which is human readable):
The File Save As menu behaves as expected, with the user always having to choose a file name.
Once a file name has been specified (either through the command line or the file selector dialog box), that file name is reused whenever the File Save menu is used. The File Save As menu may be used at any time to change the file name.
$ wish moodss randomor, for 2 modules at once:
$ wish moodss ps cpustatsYou may not specify the same module more than once in the command line.
You may eventually specify a poll time in seconds using:
$ wish moodss -p 25 randomNote that when all the specified modules are asynchronous, the poll time option specifies the preferred interval for graph viewers.
Once saved through the File Save menus (for example in save.moo) , the configuration can be retrieved using:
$ wish moodss -f save.moowhich would result in the same modules being loaded, the same viewers displayed at the same positions and sizes, the same poll time being used, as well at the same application window size.
Command line options include:
package provide random 1.1This line simply states that this is the 1.1 version of the random package. Please note that the package name must also be used as the module namespace name (see below).
namespace eval random { array set data { ... } proc update {} { ... } }The update procedure is not needed when the module is asynchronous.
All the module configuration data is stored as array members of the array named data within the module namespace. For example:
namespace eval random { array set data { updates 0 0,label name 0,type ascii 0,message {user name} 1,label cpu 1,type real 1,message {cpu usage in percent} 2,label disk 2,type integer 2,message {disk usage in megabytes} 3,label command 3,type dictionary 3,message {most time consuming command} pollTimes {10 5 20 30 60 120 300} sort {1 decreasing} indexColumns {0 3} helpText { This is a simple demonstration module ... } } ... }The updates member is a counter used to keep track of the number of times that the module data was updated, and is also used by the core to detect when module data display should be updated (see variable data for more information).
The columns member is obsolete and no longer used after and including moodss version 3.5.
The n,label members define the text to be displayed as column
titles. There must be as many n,label members as they are columns.
The n,type members define the type of the corresponding column
data. Valid types are simply those that the Tcl lsort command can
handle: ascii, dictionary, integer and real.
There must be as many n,type members as they are columns.
The n,message members define the text of the help message to
be displayed in the message area (see User Interface)
as the user moves the mouse pointer over column titles. It should be composed
of only a few words, just enough to actually help the user understand what
the column data means. There must be as many n,message members as
they are columns.
Note that column numbers start at 0.
The pollTimes member is a list of valid poll times (in seconds)
for the module. The list is not ordered, as its first element represents
the default poll time value to be used when the moodss application starts.
This value may be overridden by a command line argument. The smallest value
in the list is used by the core as the lowest possible poll time and checked
against when the user enters a new value through the poll time dialog box.
The list must not be empty.
Note that the list is also used by moodss as a set of possible choices
in the dialog box used to set the new poll time. The user may still directly
input any value as long as it is greater than or equal to the minimum value.
If the module is asynchronous (data can be updated at any time and not in response to update procedure invocations (no polling required)), the pollTimes member must be a single negative integer value representing the preferred time interval for viewers that require one (only graphs at this point). For example, if you wish graph viewers to have a display interval of 10 seconds, use:
namespace eval random { array set data { ... pollTimes -10 ... } ... }In this case, the graph viewers time range (knowing that they feature 100 time points) would be 1000 seconds. I guess that the value that you should specify as the pollTimes member should be the expected average update interval for your asynchronous data. Note that the graphical viewers x axis always display properly labelled absolute time ticks in any case.
When several asynchronous modules are loaded with no synchronous modules, the interval used for all relevant viewers is the average (in absolute value) of all module intervals. For example, if you load 2 asynchronous modules, one with a pollTimes member of -10 and the other of -20, then a 15 seconds interval value is retained. Note that the interval can be forced through the --poll-time command line argument.
If at least one synchronous module is loaded concurrently with any number of asynchronous modules, the actual application poll time (the one that can be set with the then available poll time dialog box) is used.
The visibleColumns member is an optional list that specifies the table columns that should be displayed. If not specified, all the table columns are visible.
The sort list defines the index of the column which should be initially used as a reference for sorting the data table rows, and in which order (increasing or decreasing) the rows should be sorted. The column index for sorting works like the -index Tcl lsort command option, that is rows are sorted so that that specific column appears sorted in the specified order. The specified column must be visible (see visibleColumns member documentation above).
The indexColumns list specifies the columns required to uniquely identify a row in the table. In database talk, it represents the table key. To maintain backward compatibility, it is optional and defaults to 0, the leftmost column. The index columns are used when creating data viewer elements: their label is built by concatenating the key value for the cell row with the cell column title. The key value is the concatenation of the index column values for the cell. When specified, all the columns in the list must be visible (see visibleColumns member documentation above).
The helpText member specifies a text of any length, to be displayed when the user requests help information on the current module from within the help menu.
The views member is optional. If specified, it defines one or more views to be used in place of the default view. One table will be displayed per view. Each view is a list of array members, suitable as an argument to an "array set" command. For each view, 2 members must be defined: visibleColumns and sort (syntax and usage are identical to the default table members).
For example, a recent random module configuration is as follows:
array set data { updates 0 0,label name 0,type ascii 0,message {user name} 1,label cpu 1,type real 1,message {cpu usage in percent} 2,label disk 2,type integer 2,message {disk usage in megabytes} 3,label memory 3,type integer 3,message {memory usage in kilobytes} 4,label command 4,type dictionary 4,message {command name} pollTimes {10 5 20 30 60 120 300} sort {1 decreasing} indexColumns {0 4} helpText {...} views { {visibleColumns {0 1 3 4} sort {1 decreasing}} {visibleColumns {0 2 4} sort {2 decreasing}} } }In this case, data is presented in 2 tables: one for the CPU and memory usage, the other for disk usage.
In case of a synchronous module, the core invokes the module update procedure (which obviously must exist) when it is time to refresh the data display (tables and eventually graphical viewers). At this time, the update procedure may update the tabular data straight away (synchronous operation) or launch a request for later data update (asynchronous operation).
In case of an asynchronous module, variable data may be updated at any time. The update procedure may not exist.
For all module types, it actually does not matter when the data is updated.
The core will know that fresh data is available when the updates
array member is set (actually incremented as it also serves as a counter
for the number of updates so far).
It is the module programmer's responsibility to increment this counter
right after all tabular data has been updated.
For example, retrieving information for the processes running on a machine
is a local operation that can be achieved in a reasonably small amount
of time. In such a case, data would be updated immediately and the updates
variable incremented at the same time.
But if the data has to be retrieved from across a network, waiting
for it to come back would cause a delay that the user would certainly notice,
as the application would not respond to mouse or keyboard input during
the whole time that it would take to fetch the whole data. In such cases,
it is easier to let the update procedure return immediately without setting
the updates variable, which would be incremented at a later time,
only when the data would become available. For example, when waiting for
data to come across a network connection, the Tcl fileevent command
could be used on a non blocking channel, where the script to be evaluated
when the channel becomes readable would increment the updates array
member.
For example:
namespace eval random { ... proc update {} { variable data array set data " 0,0 john 0,1 1234 0,2 4567 0,3 cc 1,0 william 1,1 8901 1,2 2345 1,3 xedit 2,0 anny 2,1 6789 2,2 0123 2,3 ps 4,0 peter 4,1 4567 4,2 8901 4,3 ls 6,0 laura 6,1 2345 6,2 6789 6,3 emacs 3,0 robert 3,1 1234 3,2 5678 3,3 top " incr data(updates) } }The tabular data array index is the row number followed by the column number separated by a comma. The column number must start from 0 up to the total number of columns minus 1 (no holes are allowed in the column sequence).
When all rows (or only those table cells that have changed) have been updated, the updates member array must be incremented so that the core knows that it can update the table data display.
The random module source code can be made to function asynchronously: please look into the random.tcl file.
package ifneeded random 1.1 "source [file join $dir random.tcl]"The line above says that if the random package is needed, the Tcl core should source the random.tcl module source code from the directory where it was installed. 1.1 is the version number for the package.
Modules can be installed at any valid place that the Tcl core allows (look at the pkg_mkIndex manual page for more information).
When you unpack moodss, you will find the sample modules in sub directories. The current directory (.) is appended to the auto_load global list variable so that sample modules can be found when moodss is run from the unpacking directory.
For example, if you unpacked moodss in /home/joe/moodss-5.x/, you will find the random module package in /home/joe/moodss-5.x/random/ so that the following will work:
$ cd /home/joe/moodss-5.x/ $ wish moodss randomYou can install your new modules in the default location: /usr/local/lib/ on Unix. For example, if you move the files in /home/joe/moodss-4.x/random/ to /usr/local/lib/random/, moodss (actually Tcl :) will still be able to find the random module (again, look at the pkg_mkIndex manual page for more information).
Please take a look at the INSTALL file for the latest information on how to install the moodss application itself.
Send your comments, complaints, ... to Jean-Luc Fontaine.